﻿using System;
using Nofs.Fuse;
using Nofs.Net.Common.Interfaces.Domain;
using Nofs.Net.nofs.metadata.interfaces;


namespace Nofs.Net.Fuse.Impl
{
    
public class DirHandler : IDirHandler
{
	private PathTranslator _lookup;
	private LockManager _lock;
	private LogManager _logger;
	private DomainObjectCollectionHelper _helper;

	public DirHandler(PathTranslator lookup, DomainObjectCollectionHelper helper, LockManager lockManager, LogManager logger) 
{
		_lookup = lookup;
		_helper = helper;
		_lock = lockManager;
		_logger = logger;
	}

	//@Override
	public int getdir(String path, FuseDirFiller filler)// throws FuseException 
    {
		int stat = 0;
		_logger.LogInfo("getdir(" + path + ")");
		try {
			_lock.Lock();
			IFileObject targetFolder = _lookup.TranslatePath(path);
			if(targetFolder == null) {
                stat = FuseErrno.ENOENT;
			} else if(targetFolder.GetGenerationType() == GenerationType.DOMAIN_FOLDER) {
				foreach(IFileObject child in _lookup.GetPathChildren(path)) {
					filler.add(
							child.GetName(),
							child.GetID().hashCode(),
							StatHandler.GetMode(child));
				}
			} else {
				_logger.LogError("getdir(" + path + ") is not a folder");
                stat = FuseErrno.ENOTDIR;
			}
		} catch(Exception e) {
			throw new FuseException("getdir(" + path  + ")", e);
		} finally {
			_lock.UnLock();
		}
		return stat;
	}

	//@Override
	public int mkdir(String path, int mode) //throws FuseException 
    {
		int stat = 0;
		_logger.LogInfo("mknod(" + path + "," + mode + ")");
		try {
			_lock.Lock();
			IFileObject target = _lookup.TranslatePath(path);
			if(target != null) {
                stat = FuseErrno.EEXIST;
			} else {
				target = _lookup.TranslatePathParent(path);
				if(target == null) {
                    stat = FuseErrno.ENOENT;
				} else if(target.GetGenerationType() != GenerationType.DOMAIN_FOLDER) {
                    stat = FuseErrno.ENOTSUPP;
				} else if(!target.CanMkdir()) {
                    stat = FuseErrno.EACCES;
				} else {
					stat = mkdir(PathUtil.GetChildName(path), target, mode);
				}
			}
		} catch(Exception e) {
			throw new FuseException("mknod(" + path + ")", e);
		} finally {
			_lock.UnLock();
		}
		return stat;
	}

	private int mkdir(String childName, IFileObject parent, int mode) //throws Exception 
    {
		if(parent.HasMethod()) {
			_helper.AddChildObject(parent.GetObject(), parent.GetMethod(), childName, MarkerTypes.FolderObject);
		} else {
			_helper.AddChildObject(parent.GetObject(), childName, MarkerTypes.FolderObject);
		}
		return 0;
	}

	//@Override
	public int rmdir(String path) //throws FuseException 
    {
		int stat = 0;
		try {
			_lock.Lock();
			IFileObject target = _lookup.TranslatePath(path);
			if(target == null) {
                stat = FuseErrno.ENOENT;
			} else {
				IFileObject targetParent = _lookup.TranslatePathParent(path);
				if(target.GetGenerationType() != GenerationType.DOMAIN_FOLDER) {
                    stat = FuseErrno.EBADF;
				} else if(targetParent.GetGenerationType() != GenerationType.DOMAIN_FOLDER) {
                    stat = FuseErrno.ENOTSUPP;
				} else if(!targetParent.CanRmdir()) {
                    stat = FuseErrno.EACCES;
				} else {
					if(targetParent.HasMethod()) {
						_helper.RemoveChildObject(targetParent.GetObject(), targetParent.GetMethod(), target.GetValue());
					} else {
						_helper.RemoveChildObject(targetParent.GetObject(), target.GetValue());
					}
				}
			}
		} catch(Exception e) {
			throw new FuseException("rmdir(" + path + ")", e);
		} finally {
			_lock.UnLock();
		}
		return stat;
	}

}
}
